using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;
using System.Threading;
using UmlDesigner.Controller;
using UmlDesigner.Model;
using UmlDesigner.Model.WorkUnits;
using System.Net;
using System.Reflection;
using WeifenLuo.WinFormsUI.Docking;
using System.Diagnostics;
using System.Xml;

namespace UmlDesigner.Gui
{
    public partial class MainForm : Form
    {
        private string helpFile = "UmlDesignerHelp.chm";

        private Thread updatesThread;

        DiagramTreeForm diagramTreeForm;

        public MainForm(string filename)
        {
            InitializeComponent();

            updatesThread = new Thread(new ThreadStart(CheckForUpdatesThread));
            updatesThread.Start();

            Icon = Properties.Resources.ApplicationIcon;
            /*
            string fullHelpPath = Path.GetDirectoryName(Path.GetFullPath(Application.ExecutablePath)) + "\\" + helpFile;

            if (!File.Exists(fullHelpPath))
            {
                helpFile = @"..\UmlDesignerHelp.chm";
                if (!File.Exists(helpFile))
                {
                    throw new Exception("Error! Missing file UmlDesignerHelp.chm. Please reinstall. (looked:" + fullHelpPath);
                }
            }
            helpProvider1.HelpNamespace = fullHelpPath;//*/

            diagramTreeForm = new DiagramTreeForm();
            diagramTreeForm.Show(dockPanel1);

            if (filename != null)
            {
                Project.Instance.LoadDataModel(filename);
            }
            else
            {
                Project.Instance.CreateNewDocument();
            }
            diagramTreeForm.Reload();

            RefreshTabs();

        }

//Update to new version methods
        private void CheckForUpdatesThread()
        {
            try
            {

                WebRequest req = WebRequest.Create("http://www.greenbirdsoftware.com/LastRelease.html");

                WebResponse resp = req.GetResponse();
                StreamReader reader = new StreamReader(resp.GetResponseStream());

                string page = reader.ReadToEnd();

                string startTag = "Last Version: \"";

                int tagStart = page.IndexOf(startTag);
                if (tagStart == -1)
                {
                    return;
                }

                page = page.Substring(tagStart + startTag.Length);

                int tagEnd = page.IndexOf("\"");
                if (tagEnd == -1)
                {
                    return;
                }

                page = page.Substring(0, tagEnd);

                // Page is now the version, just need to compare it with our current version... any 
                // difference indicates that there has been a new release.
                string asmVer = Assembly.GetExecutingAssembly().GetName().Version.ToString();
                if (GetMajorAndMinorVersions(page) != GetMajorAndMinorVersions(asmVer))
                {
                    // Its an out of date version, tell the user!
                    Invoke(new MethodInvoker(NotifyUserAboutNewRelease));
                }
            }
            catch (Exception)
            {
                // Do nothing, because if something bad happened then it 
                // doesnt really matter in the end - its only new version detection
            }
        }

        private string GetMajorAndMinorVersions(string ver)
        {
            int idx = ver.IndexOf('.');

            idx = ver.IndexOf('.', idx + 1);

            return ver.Substring(0, idx);
        }

        private void NotifyUserAboutNewRelease()
        {
            MessageBox.Show("A new version of Green Bird Software's UML Designer is currently available!\n Please consider updating to take advantage of any new features that may be available.", "New Version Available");
        }

//////////////////////////////////////
        public bool LinkState
        {
            get
            {
                return linkToolStripButton.Checked;
            }

            set
            {
                linkToolStripButton.Checked = value;
            }
        }

//Load Methods
        private void OnMenuLoad(object sender, EventArgs e)
        {
            OnLoad();
        }

        private void OnToolBarLoad(object sender, EventArgs e)
        {
            OnLoad();
        }

        private void OnLoad()
        {
            OpenFileDialog d = new OpenFileDialog();
            d.Filter = "UML Documents (*.udf)|*.udf";
            d.DefaultExt = "udf";

            if (d.ShowDialog() == DialogResult.OK)
            {
                fileName = d.FileName;

                Project.Instance.LoadDataModel(fileName);
                RefreshTabs();
                diagramTreeForm.Reload();
            }
        }

//Save Methods
        private void OnMenuSaveAs(object sender, EventArgs e)
        {
            SaveDocumentAs();
        }

        internal bool SaveDocument()
        {
            if (fileName == null)
            {
                return SaveDocumentAs();
            }
            else
            {
                SaveDocumentInternal();
                return true;
            }
        }

        internal bool SaveDocumentAs()
        {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.AddExtension = true;
            dlg.OverwritePrompt = true;
            dlg.Filter = "UML Documents (*.udf)|*.udf";
            dlg.DefaultExt = "udf";

            if (dlg.ShowDialog() == DialogResult.OK)
            {
                fileName = dlg.FileName;
                SaveDocumentInternal();
                return true;
            }
            else
            {
                return false;
            }
        }

        private void SaveDocumentInternal()
        {
            FileStream stream = new FileStream(fileName, FileMode.Create);
            Project.Instance.SaveDataModel(stream);
        }

        private void OnMenuSaveClicked(object sender, EventArgs e)
        {
            SaveDocument();
        }

        private void OnToolBarSaveClicked(object sender, EventArgs e)
        {
            SaveDocument();
        }

        private void exportAsImageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (GetCurrentPage().UmlControl.currentDocument.items.Count == 0)
            {
                return;
            }

            SaveFileDialog dlg = new SaveFileDialog();
            dlg.DefaultExt = "bmp";
            dlg.OverwritePrompt = true;
            dlg.Filter = "Bitmap Images (*.bmp)|*.bmp";

            if (dlg.ShowDialog() == DialogResult.OK)
            {
                Bitmap bmp;
                bmp = GetCurrentPage().UmlControl.GetDocumentAsImage();
                bmp.Save(dlg.FileName);
            }
        }

//Document Methods

        private void RefreshTabs()
        {

            while (GetCurrentPage() != null)
            {
                GetCurrentPage().Close();
            }

            foreach (Document d in Project.Instance.Documents)
            {
                AddNewClassDiagram(d);
            }
            diagramTreeForm.Reload();
        }

        private ClassDiagramForm GetCurrentPage()
        {
            return (ClassDiagramForm)dockPanel1.ActiveDocument;
        }

        private void AddNewClassDiagram(Document d)
        {
            ClassDiagramForm frm;
            frm = new ClassDiagramForm(d);
            frm.TabText = d.Name;
            frm.UmlControl.MainForm = this;
            frm.UmlControl.ResizeDocument(new Size(1600, 1200));
            frm.Show(dockPanel1);
            diagramTreeForm.Reload();
        }

        private void OnNewToolBarItemClicked(object sender, EventArgs e)
        {
            CreateNewDocument();
        }

        private void OnNewMenuItemClicked(object sender, EventArgs e)
        {
            CreateNewDocument();
        }

        private void resizeDocumentToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ResizeDocumentForm dlg = new ResizeDocumentForm(GetCurrentPage().UmlControl);
            dlg.ShowDialog();
        }

        private void newClassDiagramToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddNewClassDiagram(Project.Instance.CreateNewDocument());
        }

        private string fileName = null;

        internal void CreateNewDocument()
        {

            if (Project.Instance.Modified)
            {
                ModifiedWarningDialog dlg = new ModifiedWarningDialog();
                DialogResult result = dlg.ShowDialog(this);
                switch (result)
                {
                    case DialogResult.Cancel:
                        // Bail out at this point, because the user doesnt want to continue.
                        return;

                    case DialogResult.OK:
                        // A bit hacky, but the ok button in this case means save first before
                        // overwriting.
                        SaveDocument();
                        break;

                    default:
                        // Do nothing and discard the changes.
                        break;
                }

            }

            fileName = null;
            Project.Instance.DeleteAllDocuments();
            GetCurrentPage().UmlControl.currentDocument = Project.Instance.CreateNewDocument();
            GetCurrentPage().UmlControl.currentDocument.isModified = false;
            RefreshTabs();
            Invalidate();
        }

        private void newClassDiagramToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            AddNewClassDiagram(Project.Instance.CreateNewDocument());
        }

        private void deleteDiagramToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("This will permenantly delete the currently active diagram. Are you sure?", "Delete Diagram", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK)
            {
                Project.Instance.Documents.Remove(GetCurrentPage().UmlControl.currentDocument);
                RefreshTabs();
            }
        }

        private void renameDiagramToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RenameDiagramForm form = new RenameDiagramForm(GetCurrentPage().UmlControl.currentDocument.Name);
            if (form.ShowDialog() == DialogResult.OK)
            {
                GetCurrentPage().UmlControl.currentDocument.Name = form.DiagramName;
                RefreshTabs();
            }
        }

        private void dockPanel1_ActiveDocumentChanged(object sender, EventArgs e)
        {
            if (GetCurrentPage() != null)
            {
                UpdateZoomField();
                history.UmlControl = GetCurrentPage().UmlControl;
            }

            if (GetCurrentPage() != null && GetCurrentPage().GetType() == typeof(ClassDiagramForm))
            {
                newClassToolStripMenuItem.Enabled = true;
                newNoteToolStripMenuItem.Enabled = true;
                newFolderToolStripMenuItem.Enabled = true;
                exportAsImageToolStripMenuItem.Enabled = true;

                classToolStripButton.Enabled = true;
                noteToolStripButton.Enabled = true;
                folderToolStripButton.Enabled = true;
                linkToolStripButton.Enabled = true;

                topAlignToolStripButton.Enabled = true;
                bottomAlignToolStripButton.Enabled = true;
                leftAlignToolStripButton.Enabled = true;
                rightAlignToolStripButton.Enabled = true;

                copyToolStripButton.Enabled = true;
                copyToolStripMenuItem1.Enabled = true;
                pasteToolStripButton.Enabled = true;
                pasteToolStripMenuItem1.Enabled = true;
                cutToolStripButton.Enabled = true;
                cutToolStripMenuItem1.Enabled = true;
                deleteToolStripMenuItem.Enabled = true;

                printPreviewToolStripMenuItem.Enabled = true;
                printToolStripButton.Enabled = true;
                printToolStripMenuItem1.Enabled = true;

                compositeToolStripMenuItem.Enabled = true;
                modelViewControllerToolStripMenuItem.Enabled = true;

                horizontallyToolStripMenuItem.Enabled = true;
                horizSpaceToolStripButton.Enabled = true;
                verticallyToolStripMenuItem.Enabled = true;
                vertSpaceToolStripButton.Enabled = true;

                resizeDocumentToolStripMenuItem.Enabled = true;
                topToolStripMenuItem.Enabled = true;
                leftToolStripMenuItem.Enabled = true;
                bottomToolStripMenuItem.Enabled = true;
                rightToolStripMenuItem.Enabled = true;

                selectAllToolStripMenuItem1.Enabled = true;
            }
            else
            {
                newClassToolStripMenuItem.Enabled = false;
                newNoteToolStripMenuItem.Enabled = false;
                newFolderToolStripMenuItem.Enabled = false;
                exportAsImageToolStripMenuItem.Enabled = false;

                classToolStripButton.Enabled = false;
                noteToolStripButton.Enabled = false;
                folderToolStripButton.Enabled = false;
                linkToolStripButton.Enabled = false;

                topAlignToolStripButton.Enabled = false;
                bottomAlignToolStripButton.Enabled = false;
                leftAlignToolStripButton.Enabled = false;
                rightAlignToolStripButton.Enabled = false;

                copyToolStripButton.Enabled = false;
                copyToolStripMenuItem1.Enabled = false;
                pasteToolStripButton.Enabled = false;
                pasteToolStripMenuItem1.Enabled = false;
                cutToolStripButton.Enabled = false;
                cutToolStripMenuItem1.Enabled = false;
                deleteToolStripMenuItem.Enabled = false;

                printPreviewToolStripMenuItem.Enabled = false;
                printToolStripButton.Enabled = false;
                printToolStripMenuItem1.Enabled = false;

                compositeToolStripMenuItem.Enabled = false;
                modelViewControllerToolStripMenuItem.Enabled = false;

                horizontallyToolStripMenuItem.Enabled = false;
                horizSpaceToolStripButton.Enabled = false;
                verticallyToolStripMenuItem.Enabled = false;
                vertSpaceToolStripButton.Enabled = false;

                resizeDocumentToolStripMenuItem.Enabled = false;
                topToolStripMenuItem.Enabled = false;
                leftToolStripMenuItem.Enabled = false;
                bottomToolStripMenuItem.Enabled = false;
                rightToolStripMenuItem.Enabled = false;

                selectAllToolStripMenuItem1.Enabled = false;
            }
        }

//Add Class Methods
        private int lastAdditionNum = 1;

        private void OnNewClass(object sender, EventArgs e)
        {
            AddNewClass();
        }

        private void AddNewClass()
        {
            ClassWidget c = new ClassWidget();
            c.name = "Class" + lastAdditionNum.ToString();
            c.SetClassPosition(GetCurrentPage().GetNewItemPosition());
            lastAdditionNum++;

            NewItemWorkUnit workUnit = new NewItemWorkUnit(c);
            AddWorkUnit(workUnit);
        }

        private void newClassToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddNewClass();
        }

//Add Note Methods
        private void OnNewNote(object sender, EventArgs e)
        {
            AddNewNote();
        }

        private void AddNewNote()
        {
            NoteWidget n = new NoteWidget();
            n.SetClassPosition(GetCurrentPage().GetNewItemPosition());
            lastAdditionNum++;

            NewItemWorkUnit workUnit = new NewItemWorkUnit(n);
            AddWorkUnit(workUnit);
        }

        private void newNoteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddNewNote();
        }

//Add folder
        private void folderToolStripButton_Click(object sender, EventArgs e)
        {
            AddFolder();
        }

        private void AddFolder()
        {
            FolderWidget c = new FolderWidget();
            c.name = "Folder" + lastAdditionNum.ToString();
            c.SetClassPosition(GetCurrentPage().GetNewItemPosition());

            lastAdditionNum++;

            NewItemWorkUnit workUnit = new NewItemWorkUnit(c);
            AddWorkUnit(workUnit);
        }

        private void newFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddFolder();
        }

//Undo, Redo Methods
        History history = new History();

        internal void AddWorkUnit(IWorkUnit workUnit)
        {
            history.Add(workUnit);           
        }

        private void undoToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            history.Undo();
        }

        private void redoToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            history.Redo();
        }

//Align Methods
        private void OnAlignTopClicked(object sender, EventArgs e)
        {
            GetCurrentPage().UmlControl.AlignSelectionToTop();
        }

        private void OnAlignLeftClicked(object sender, EventArgs e)
        {
            GetCurrentPage().UmlControl.AlignSelectionToLeft();
        }

        private void OnAlignBottomClicked(object sender, EventArgs e)
        {
            GetCurrentPage().UmlControl.AlignSelectionToBottom();
        }

        private void OnAlignRightClicked(object sender, EventArgs e)
        {
            GetCurrentPage().UmlControl.AlignSelectionToRight();
        }

        private void horizSpaceToolStripButton_Click(object sender, EventArgs e)
        {
            GetCurrentPage().UmlControl.DistributeSpaceHorizontally();
        }

        private void vertSpaceToolStripButton_Click(object sender, EventArgs e)
        {
            GetCurrentPage().UmlControl.DistributeSpaceVertically();
        }

        private void horizontallyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GetCurrentPage().UmlControl.DistributeSpaceHorizontally();
        }

        private void verticallyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GetCurrentPage().UmlControl.DistributeSpaceVertically();
        }

//Exit
        private void OnExitClicked(object sender, EventArgs e)
        {
            Close();
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (GetCurrentPage() != null && GetCurrentPage().UmlControl.currentDocument.isModified)
            {
                bool exitCaseDecided = false;
                while (!exitCaseDecided)
                {
                    ModifiedWarningDialog dlg = new ModifiedWarningDialog();
                    DialogResult result = dlg.ShowDialog(this);
                    switch (result)
                    {
                        case DialogResult.Cancel:
                            // Bail out at this point, because the user doesnt want to continue.
                            e.Cancel = true;
                            exitCaseDecided = true;
                            return;

                        case DialogResult.OK:
                            // A bit hacky, but the ok button in this case means save first before
                            // exiting.
                            exitCaseDecided = SaveDocument();
                            break;

                        default:
                            // Continue closing and discard the changes.
                            exitCaseDecided = true;
                            break;
                    }
                }
            }
        }

//Edit
        private void selectAllToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            GetCurrentPage().UmlControl.selection.Clear();
            GetCurrentPage().UmlControl.selection.AddRange(GetCurrentPage().UmlControl.currentDocument.items);
        }

        private void OnCutClicked(object sender, EventArgs e)
        {
            GetCurrentPage().UmlControl.CutSelectionToClipboard();
        }

        private void OnCopyClicked(object sender, EventArgs e)
        {
            GetCurrentPage().UmlControl.CopySelectionToClipboard();
        }

        private void OnPasteClicked(object sender, EventArgs e)
        {
            Document d = UmlClipboardData.CreateFromClipboard();
            if (d != null)
            {

                if (d.items.Count == 0)
                {
                    return;
                }

                // Find the top left object position...
                Point topLeftPos = d.items[0].GetClassPosition();

                foreach (ItemWidget i in d.items)
                {
                    if (!i.IsLink())
                    {
                        Point itemPos = i.GetClassPosition();
                        if (topLeftPos.X > itemPos.X)
                        {
                            topLeftPos.X = itemPos.X;
                        }
                        if (topLeftPos.Y > itemPos.Y)
                        {
                            topLeftPos.Y = itemPos.Y;
                        }
                    }
                }

                GetCurrentPage().UmlControl.currentDocument.MergeDocument(d);

                GetCurrentPage().UmlControl.selection.Clear();
                GetCurrentPage().UmlControl.Invalidate();
            }

        }

        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GetCurrentPage().UmlControl.DeleteSelection();
        }

//Code Generation
        private void OnCodeGenerateClicked(object sender, EventArgs e)
        {
            CodeGenerationForm codeGenerationForm = new CodeGenerationForm("UmlDesignerGeneratedCode");
            if (codeGenerationForm.ShowDialog(this) == DialogResult.OK)
            {
                Directory.CreateDirectory(codeGenerationForm.GenerationSettings.OutputDirectory);

                // Handle any solution/project file generation
                string slnDir = codeGenerationForm.GenerationSettings.OutputDirectory;
                string projDir;
                if (codeGenerationForm.GenerationSettings.CreateDirForProject)
                {
                    projDir = Path.Combine(slnDir, codeGenerationForm.GenerationSettings.DefaultNamespace);
                    Directory.CreateDirectory(projDir);
                }
                else
                {
                    projDir = slnDir;
                }
                codeGenerationForm.GenerationSettings.OutputDirectory = projDir;

                if (codeGenerationForm.GenerationSettings.Source == CodeGenerationSettings.GenerationSource.SelectionOnly)
                {
                    GetCurrentPage().UmlControl.currentDocument.GenerateCode(codeGenerationForm.GenerationSettings, GetCurrentPage().UmlControl.selection);
                }
                else
                {
                    if (codeGenerationForm.GenerationSettings.Source == CodeGenerationSettings.GenerationSource.AllDocuments)
                    {
                        foreach (Document doc in Project.Instance.Documents)
                        {
                            doc.GenerateCode(codeGenerationForm.GenerationSettings, doc.items);
                        }
                    }
                    else
                    {
                        GetCurrentPage().UmlControl.currentDocument.GenerateCode(codeGenerationForm.GenerationSettings, GetCurrentPage().UmlControl.currentDocument.items);
                    }
                }
                codeGenerationForm.GenerationSettings.FinishCurrentItem();

                if (codeGenerationForm.GenerationSettings.CreateProject)
                {
                    GenerateProjectFile(projDir, codeGenerationForm.GenerationSettings);
                }
                if (codeGenerationForm.GenerationSettings.CreateSolution)
                {
                    GenerateSolutionFile(slnDir, codeGenerationForm.GenerationSettings);
                }

                // Display the results.
                CodeGenerationResultsForm resultsForm = new CodeGenerationResultsForm();
                resultsForm.ShowResults(codeGenerationForm.GenerationSettings.Errors.ToString());
                resultsForm.ShowDialog();
            }
        }

        private void GenerateSolutionFile(string slnDir, CodeGenerationSettings codeGenerationSettings)
        {
            //throw new NotImplementedException();

            // <<PROJECT_INTRO_LINE>> looks like:
            // Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemplateProject", "TemplateProject\TemplateProject.csproj", "{1D5E431A-8806-4991-B68D-024F433BA9D3}"

            // <<PROJECT_CONFIG_BLOCK>>
            //{1D5E431A-8806-4991-B68D-024F433BA9D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
            //{1D5E431A-8806-4991-B68D-024F433BA9D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
            //{1D5E431A-8806-4991-B68D-024F433BA9D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
            //{1D5E431A-8806-4991-B68D-024F433BA9D3}.Release|Any CPU.Build.0 = Release|Any CPU

            // Note: The guids need to match up with the guid in the csproj file.

        }

        private void GenerateProjectFile(string projDir, CodeGenerationSettings codeGenerationSettings)
        {
            XmlDocument doc = new XmlDocument();

            // Need to remove the first line to remove the encoding because microsofts XML parser 
            // is mental and cant cope with xpath if the encoding is UTF-8.
            doc.LoadXml(Properties.Resources.TemplateProject);
            XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
            nsManager.AddNamespace("a", "http://schemas.microsoft.com/developer/msbuild/2003");
            XmlNode insertAfterPoint = doc.SelectSingleNode("/a:Project/a:ItemGroup/a:Compile[@Include='TEMPLATE FILENAME']", nsManager);

            foreach (string filename in codeGenerationSettings.ProcessedFiles)
            {
                XmlNode node = insertAfterPoint.CloneNode(true);
                node.Attributes["Include"].Value = Path.GetFileName(filename);
                insertAfterPoint.ParentNode.InsertAfter(node, insertAfterPoint);
            }

            insertAfterPoint.ParentNode.RemoveChild(insertAfterPoint);
            doc.Save(Path.Combine(projDir, codeGenerationSettings.DefaultNamespace + ".csproj"));
        }

//Print
        Point currentPrintOrigin;
        Bitmap currentlyPrinting;

        private void printPreviewToolStripMenuItem_Click(object sender, EventArgs e)
        {
            currentlyPrinting = GetCurrentPage().UmlControl.GetDocumentAsImage();
            if (currentlyPrinting != null)
            {
                currentPrintOrigin = new Point(0, 0);

                PrintDocument doc = new PrintDocument();
                doc.PrintPage += new PrintPageEventHandler(doc_PrintPage);
                PrintPreviewDialog dlg = new PrintPreviewDialog();
                dlg.Document = doc;
                dlg.ClientSize = new Size(600, 600);
                dlg.Icon = Properties.Resources.ApplicationIcon;
                dlg.StartPosition = FormStartPosition.CenterParent;

                dlg.ShowDialog(this);
            }
        }

        private void printToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            currentlyPrinting = GetCurrentPage().UmlControl.GetDocumentAsImage();
            if (currentlyPrinting != null)
            {
                currentPrintOrigin = new Point(0, 0);

                PrintDocument doc = new PrintDocument();
                doc.PrintPage += new PrintPageEventHandler(doc_PrintPage);
                PrintDialog dlg = new PrintDialog();
                dlg.Document = doc;
                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    doc.Print();
                }
            }
        }

        void doc_PrintPage(object sender, PrintPageEventArgs e)
        {
            Size drawSize = new Size();

            drawSize.Width = (Math.Min(e.MarginBounds.Width, currentlyPrinting.Width - currentPrintOrigin.X));
            drawSize.Height = (Math.Min(e.MarginBounds.Height, currentlyPrinting.Height - currentPrintOrigin.Y));

            Rectangle srcRect = new Rectangle(currentPrintOrigin, drawSize);
            Rectangle destRect = new Rectangle(e.MarginBounds.Location, drawSize);

            e.Graphics.DrawImage(currentlyPrinting, destRect, srcRect, GraphicsUnit.Pixel);

            if (currentPrintOrigin.X + drawSize.Width == currentlyPrinting.Width
                && currentPrintOrigin.Y + drawSize.Height == currentlyPrinting.Height)
            {
                e.HasMorePages = false;
            }
            else
            {
                e.HasMorePages = true;

                if (currentPrintOrigin.X + drawSize.Width == currentlyPrinting.Width)
                {
                    currentPrintOrigin.Y += drawSize.Height;
                    currentPrintOrigin.X = 0;
                }
                else
                {
                    currentPrintOrigin.X += drawSize.Width;
                }
            }
        }

//Help
        private void aboutToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            AboutBox aboutBox = new AboutBox();
            aboutBox.ShowDialog();
        }

        private void contentsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            HelpNavigator navigator = HelpNavigator.TableOfContents;
            Help.ShowHelp(this, helpFile, navigator);
        }

        private void indexToolStripMenuItem_Click(object sender, EventArgs e)
        {
            HelpNavigator navigator = HelpNavigator.Index;
            Help.ShowHelp(this, helpFile, navigator);
        }

        private void searchToolStripMenuItem_Click(object sender, EventArgs e)
        {
            HelpNavigator navigator = HelpNavigator.Find;
            Help.ShowHelp(this, helpFile, navigator);
        }

        private void OnResize(object sender, EventArgs e)
        {
            int width = ClientRectangle.Width;
            int height = ClientRectangle.Height - toolStripContainer1.TopToolStripPanel.Size.Height - statusStrip1.Size.Height - 25;
            dockPanel1.Size = new Size(width, height);
            dockPanel1.Location = new Point(0, toolStripContainer1.TopToolStripPanel.Size.Height);
            RecalculateUmlControlSize();
        }

        internal void RecalculateUmlControlSize()
        {
            //Size docSize = GetCurrentPage().UmlControl.GetDocumentSize();
            //Size newSize = new Size();

            //newSize.Width = Math.Max(scrollingPanel.ClientSize.Width, docSize.Width);
            //newSize.Height = Math.Max(scrollingPanel.ClientSize.Height, docSize.Height);

            //if (GetCurrentPage().UmlControl.Size != newSize)
            //{
            //    GetCurrentPage().UmlControl.Size = newSize;
            //}
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
#if DEBUG
            debuggingToolStripMenuItem.Visible = true;
            debuggingToolStripMenuItem.Enabled = true;
#endif
        }

//Debug
        private void diagnosticsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DataModelDiagnosticsForm diagnosticsForm = new DataModelDiagnosticsForm();
            diagnosticsForm.DumpDataModel(GetCurrentPage().UmlControl.currentDocument);
            diagnosticsForm.Show();
        }

//Pattern menu
        private void modelViewControllerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GetCurrentPage().UmlControl.MergeLoadFromBytes(Properties.Resources.MvcPattern);
        }

        private void compositeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GetCurrentPage().UmlControl.MergeLoadFromBytes(Properties.Resources.Composite);
        }

//Scale menu
        private void toolStripMenuItem4_Click(object sender, EventArgs e)
        {
            ScaleUmlControl(1.0f);
        }

        private void toolStripMenuItem5_Click(object sender, EventArgs e)
        {
            ScaleUmlControl(0.8f);
        }

        private void toolStripMenuItem8_Click(object sender, EventArgs e)
        {
            ScaleUmlControl(0.6f);
        }

        private void toolStripMenuItem6_Click(object sender, EventArgs e)
        {
            ScaleUmlControl(0.4f);
        }

        private void toolStripMenuItem7_Click(object sender, EventArgs e)
        {
            ScaleUmlControl(0.2f);
        }

        private void ScaleUmlControl(float amount)
        {
            GetCurrentPage().UmlControl.SetScalingFactor(amount);
            UpdateZoomField();
        }

        private void UpdateZoomField()
        {
            scaleToolStripDropDownButton.Text = "Zoom: " + GetScalingFactorAsText(GetCurrentPage().UmlControl.GetScalingFactor()) + "%";
        }

        private static string GetScalingFactorAsText(float amount)
        {
            return ((int)(amount * 100.0f)).ToString();
        }

        protected override Point ScrollToControl(Control activeControl)
        {
            return DisplayRectangle.Location;
        }

        private void newFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            NewFileDialog nfd = new NewFileDialog();
            nfd.ShowDialog();
        }
    }
}
